Features to Implement/Fix
=========================
Fix the horrid TasksUpdate/IsValidWindow code, where the title/class text is read multiple times.

2004-02-09: (RabidCow)
----------------------
OnMouseOver, OnMouseOut, OnHover, OnUnhover
- These are not yet implemented, but it will read the settings.  IIRC, they should work like so:
  OnMouseOver: WM_MOUSEMOVE: if (!MouseIn(iTile)) { Exec(); SetMouseInTile(iTile); SetCapture(iTile); }
  OnMouseOut:  WM_MOUSEMOVE: if (MouseIn(iTile) && WindowFromPoint(pt)!=iTile) { Exec(); ClearMouseInTile(iTile); ReleaseCapture(); }
               (must check OnMouseOut before OnMouseOver)
  OnHover:     WM_MOUSEMOVE: SetTimer(); SaveMouseMovePos();
               WM_TIMER: if (!Hovering() && MousePos()==LastMouseMovePos()) { Exec(); SetHover(); SetHoverPos(); }
  OnUnhover:   WM_MOUSEMOVE: if (Hovering() && MousePos()!=MouseHoverPos()) { Exec(); ClearHover(); }
- I don't know if these will be very useful without some form of local variable expansion.


ideas:
------
Real flashing for task buttons.  NOTE: Basic support implemented, using "Selected" display state.
MouseOver/Down highlighting
Wharf support
Update task control bang commands to control single tasks as well as all tasks.
Work on WrapCmd stuff, add *TasksCmd x "cmd".  NOTE: currently onAdd/Del is supported
Look into other sorting options.

known bugs:
-----------
Dragging causes some bad paint artifacts, especially when docked and transparency is enabled.


current working notes:
======================

  OnMouseOut:  WM_MOUSEMOVE:
	if(MouseIn(iTile) && WindowFromPoint(pt) != iTile)
	{
		Exec(OnMouseOut);
		ClearMouseInTile(iTile);
		ReleaseCapture();
	}
               
   (must check OnMouseOut before OnMouseOver)

  OnMouseOver: WM_MOUSEMOVE:
	else if(!MouseIn(iTile))
	{
		Exec(OnMouseOver);
		SetMouseInTile(iTile);
		SetCapture(iTile);
	}

  OnHover:     WM_MOUSEMOVE:
	SetTimer();
	SaveMouseMovePos();

               WM_TIMER:
	if(!Hovering() && MousePos() == LastMouseMovePos())
	{
		Exec();
		SetHover();
		SetHoverPos();
	}

  OnUnhover:   WM_MOUSEMOVE:
	if(Hovering() && MousePos() != MouseHoverPos())
	{
		Exec();
		ClearHover();
	}


EOF



















=================
	case WM_LBUTTONUP:
	{
		if(-1 != capLClick)
		{
			POINT cursorPos;
			BOOL bMoved = FALSE;

			if(!ts.NoMove)
			{
				int x, y;

				GetCursorPos(&cursorPos);

				x = tasks[capLClick].x - (oldCursorPos.x - cursorPos.x);
				y = tasks[capLClick].y - (oldCursorPos.y - cursorPos.y);

				if (x < 0) x = 0;
				if (y < 0) y = 0;
				if (x + ts.Width > g_nDockCX) x = g_nDockCX - ts.Width;
				if (y + ts.Height > g_nDockCY) y = g_nDockCY - ts.Height;

				if(
					abs(tasks[capLClick].x - x) > ts.DragDistance
					||
					abs(tasks[capLClick].y - y) > ts.DragDistance
				)
				{
					bMoved = TRUE:
				}
			}

			int n = GetTaskByWnd(WindowFromPoint(cursorPos));

			if(capLClick != n) /* 'onUp' must happen on same task as 'onDown' */
			{
				n = capLClick;

				if(!ts.NoMove)
				{
					/* Make sure we are in our final position */
					SetWindowPos(
						 tasks[n].hWnd
						,0
						,tasks[n].x
						,tasks[n].y
						,0
						,0
						,SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE|SWP_NOOWNERZORDER
					);
				}

				capLClick = -1;
				ReleaseCapture(); // need to release capture before focus changes

				DoMouseCommand(n, ts.OnLButtonUp);

				SwitchToWnd(hWnd == curTask ? lockCurTask:oldCurTask);
				lockCurTask = NULL;
			}
			else if( /* process event as a click */
				ts.NoMove
				||
				(
					abs(oldCursorPos.x - cursorPos.x) <= ts.DragDistance
					&&
					abs(oldCursorPos.y - cursorPos.y) <= ts.DragDistance
				)
			)
			{
				if(!ts.NoMove)
				{
					/* Make sure we are in our final position */
					SetWindowPos(
						 tasks[n].hWnd
						,0
						,tasks[n].x
						,tasks[n].y
						,0
						,0
						,SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE|SWP_NOOWNERZORDER
					);
				}

				capLClick = -1;
				ReleaseCapture(); // need to release capture before focus changes

				/* Before sending a WS_SYSCOMMAND, a window must have focus for it to work correcly */
				/* So put activation of the app here, instead of after the MinimizeOnClick check. */
				SwitchToTasksWnd(n);

				if(
					!ts.NoMinimizeOnClick
					&&
					!tasks[n].IsIconic
					&&
					(
						tasks[n].appHandle == curTask
						||
						(tasks[n].hWnd == curTask && tasks[n].appHandle == lockCurTask)
					)
				)
				{
					SendMessage(tasks[n].appHandle2, WM_SYSCOMMAND, (WPARAM)SC_MINIMIZE, 0);
				}

				DoMouseCommand(n, ts.OnLButtonUp);
				DoMouseCommand(n, ts.OnLButtonClick);

				lockCurTask = NULL;
			}
			else /*move*/
			{
				int tmpoldx, tmpoldy;
				tmpoldx = tasks[n].x;
				tmpoldy = tasks[n].y;
				tasks[n].x -= oldCursorPos.x - cursorPos.x;
				tasks[n].y -= oldCursorPos.y - cursorPos.y;
				if (tasks[n].x < 0) tasks[n].x = 0;
				if (tasks[n].y < 0) tasks[n].y = 0;
				if (tasks[n].x + ts.Width > g_nDockCX) tasks[n].x = g_nDockCX - ts.Width;
				if (tasks[n].y + ts.Height > g_nDockCY) tasks[n].y = g_nDockCY - ts.Height;
				if (ts.MoveAll)
				{
					BOOL wasHidden = ts.StartHidden;
					ts.X -= tmpoldx - tasks[n].x;
					ts.Y -= tmpoldy - tasks[n].y;
					if (ts.X < 0)
						ts.X = ((ts.Direction == 4 || (g_bTaskWrap && ts.WrapDirection == 4))) ? 1:0;
					if (ts.Y < 0)
						ts.Y = ((ts.Direction == 1 || (g_bTaskWrap && ts.WrapDirection == 1))) ? 1:0;
					if (!wasHidden)
						TasksHide(NULL, NULL);
					rAllTasks.left = rAllTasks.right = rAllTasks.top = rAllTasks.bottom = 0;
					ReArrangeTasks(0, TRUE);
					if (rAllTasks.right > g_nDockCX){
						if (ts.Direction == 4 || (g_bTaskWrap && ts.WrapDirection == 4))
							ts.X = g_nDockCX;
						else
							ts.X -= rAllTasks.right - g_nDockCX;
					}
					if (rAllTasks.bottom > g_nDockCY){
						if (ts.Direction == 1 || (g_bTaskWrap && ts.WrapDirection == 1))
							ts.Y = g_nDockCY;
						else
							ts.Y -= rAllTasks.bottom - g_nDockCY;
					}
					if (rAllTasks.left < 0){
						if (ts.Direction == 4 || (g_bTaskWrap && ts.WrapDirection == 4))
							ts.X -= rAllTasks.left;
						else
							ts.X = 0;
					}
					if (rAllTasks.top < 0){
						if (ts.Direction == 1 || (g_bTaskWrap && ts.WrapDirection == 1))
							ts.Y -= rAllTasks.top;
						else
							ts.Y = 0;
					}
					rAllTasks.left = rAllTasks.right = rAllTasks.top = rAllTasks.bottom = 0;
					if (!wasHidden)
						TasksShow(NULL, NULL);
					ReArrangeTasks(0, TRUE);
				}
				else
				{
					SetWindowPos(
						 tasks[n].hWnd
						,0
						,tasks[n].x
						,tasks[n].y
						,0
						,0
						,SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOSIZE|SWP_NOOWNERZORDER
					);

					if(!tasks[n].IsMoved)
					{
						tasks[n].IsMoved = TRUE;

						if(ts.AutoArrange)
						{
							ReArrangeTasks(n, FALSE);

							DoWrapCommand(GetUnMovedNrTasks(numTasks) + 1);
						}
					}
				}

				capLClick = -1;
				ReleaseCapture(); // need to release capture before focus changes

				SwitchToWnd(tasks[n].IsActive ? tasks[n].appHandle2:lockCurTask);

				DoMouseCommand(n, ts.OnLButtonUp);

				lockCurTask = NULL;
			}

			if(!ts.NoMove)
			{
				SetCursor(g_hCursorNormal);
			}

			return 0;
		}
		break;
	}


===============================


		if(-1 != capLClick && !ts.NoMove && MK_LBUTTON == (MK_LBUTTON & wParam))
		{
			int x, y;
			POINT cursorPos;
			BOOL bUpdate = FALSE;

			GetCursorPos(&cursorPos);

			x = tasks[capLClick].x;
			y = tasks[capLClick].y;

			/* Set the cursor depending if we have 'moved' or not */
			if(
				abs(oldCursorPos.x - cursorPos.x) <= ts.DragDistance
				&&
				abs(oldCursorPos.y - cursorPos.y) <= ts.DragDistance
			)
			{
				if(GetCursor() != g_hCursorNormal)
				{
					SetCursor(g_hCursorNormal);
					bUpdate = TRUE;
				}
			}
			else
			{
				SetCursor(g_hCursorMoving);

				/* Move the task tile */
				x = tasks[capLClick].x - (oldCursorPos.x - cursorPos.x);
				y = tasks[capLClick].y - (oldCursorPos.y - cursorPos.y);

				if (x < 0) x = 0;
				if (y < 0) y = 0;
				if (x + ts.Width > g_nDockCX) x = g_nDockCX - ts.Width;
				if (y + ts.Height > g_nDockCY) y = g_nDockCY - ts.Height;
				bUpdate = TRUE;
			}

			if(bUpdate)
			{
				SetWindowPos(hWnd, HWND_TOP, x, y, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOOWNERZORDER);
				//InvalidateRect(ts.DockWindow, NULL, TRUE);

				/* psuedo transparency during move, causes some flicker, but it works (Maduin)*/
				if(!ts.StartHidden && ts.Transparency == 1)
				{
					InvalidateRect(hWnd, NULL, TRUE);
				}
			}

			return 0;
		}
		else //if(-1 == capLClick && -1 == capRClick && -1 == capMClick) // allow these events if a button is pressed?
		{
			/* TODO: OnMouseOver, OnMouseOut, OnHover, OnUnhover */
		}

		SetCursor(g_hCursorNormal);
